/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFDetectorManager
  \brief To manager the creation and registration of detectors according to the users'
  intention. It also by-the-way do the channel-mapping work.
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-26
  \date 2021-11-30 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-26   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#ifndef ETFDetectorManager_h
#define ETFDetectorManager_h

#include <vector>
#include <map>
#include <string>

using std::vector;
using std::string;
using std::map;

class TGraph;
class ETFDetector;
class ETFRawChannel;
class ETFParaManager;

class ETFDetectorManager{
public:
  static ETFDetectorManager *Instance();
  virtual ~ETFDetectorManager();

  /// identify ch as a hit and add to a specific detector
  virtual void Assign(ETFRawChannel *ch);
  virtual void PostAssign(); ///< finish the processing of all the assigned data
  virtual void Reset(); ///< clear the data for next event
  void SetEventIndex(int i){ fEventIndex = i; }
  void SetChMap(int chid, unsigned uid);
  virtual void Draw(); ///< draw the detector and highlight the hits
  virtual void Register(); ///< register all dets to main tree
  virtual void Configure(); ///< create the detectors w.r.t. config file
  virtual void Print(); ///< print the detector info

  unsigned GetUID(int chid) const;
  const map<string, ETFDetector *> &GetDetectorMap() const{ return fDetMap; }  
  bool HasDetector(const string &name) const{ return fDetMap.count(name); }
  /// \param warn: whether issue an warning if det is not found
  ETFDetector *GetDetector(const string &name, bool warn = false) const;
  /// retrieve detector by detector id
  /// \param warn: whether issue an warning if det is not found
  ETFDetector *GetDetector(int detId, bool warn = false) const;

  double GetTargetZ() const{ return fTargetZ; }
  int GetEventIndex() const{ return fEventIndex; }
  int Index() const{ return fEventIndex; }
  void SetDebug(bool opt = true){ fDebug = opt; }

  static constexpr int CH_MAX = 10000;
  // ClassDef(ETFDetectorManager, 0);

private:
  ETFDetectorManager();
  static ETFDetectorManager *fInstance;

protected:
  /// record det
  virtual void Record(ETFDetector *det, const char *name);
  virtual void ConfigureDraw(); ///< draw the dipole magnet and the neutral beamline

  map<string, ETFDetector *> fDetMap; ///< map<detName, det> created detector list
  vector<ETFDetector *>fDets; ///< fDets[detId] = det
  unsigned fChMap[CH_MAX]; ///< channel id map: <chId, UID>
  double fTargetZ; ///< target z position
  int fEventIndex; ///< event index for the current event
  bool fDebug; ///< print each channel after assignment

  ETFParaManager *fpm;
  TGraph *fGMagnet, *fGBeamLine; //! ///< for drawing the dipole magnet and the beamline
  TGraph *fGTarget; //! ///< for drawing the target
};

#endif
